/*
 * @Author: crissu 13750782397@163.com
 * @Date: 2024-06-04 01:28:09
 * @LastEditors: crissu 13750782397@163.com
 * @LastEditTime: 2024-06-04 01:41:48
 * @FilePath: /try_concurrence/Patterns/TeeChannel.go
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
package patterns

import (
	"fmt"
	"time"
)

// 传递一个可读取的通道给它,它会返回两个独立的通道,这两个通道会获得相同的值。
func TryTeeChannel() {
	repeat := func(done <-chan interface{}, values ...interface{}) <-chan interface{} {
		valueStream := make(chan interface{})
		go func() {
			defer close(valueStream)
			for {
				for _, v := range values {
					select {
					case <-done:
						return
					case valueStream <- v:
					}
				}
			}
		}()
		return valueStream
	}
	take := func(done <-chan interface{}, valueStream <-chan interface{}, nums int) <-chan interface{} {
		takeStream := make(chan interface{})
		go func() {
			defer close(takeStream)
			for {

				for i := 0; i < nums; i++ {
					select {
					case <-done:
						return
					case takeStream <- <-valueStream:
					}
				}
			}
		}()

		return takeStream
	}

	orDone := func(done <-chan interface{}, c <-chan interface{}) <-chan interface{} {
		valStream := make(chan interface{})
		go func() {
			defer close(valStream)
			for {
				select {
				case <-done:
					fmt.Println("finish")
					return
				case v, ok := <-c:
					if !ok {
						return
					}
					select {
					case valStream <- v:
					case <-done:
					}
				}
			}
		}()

		return valStream
	}
	tee := func(done <-chan interface{}, in <-chan interface{}) (_, _ <-chan interface{}) {
		out1, out2 := make(chan interface{}), make(chan interface{})
		go func() {
			defer close(out1)
			defer close(out2)
			for val := range orDone(done, in) {
				var out1, out2 = out1, out2
				for i := 0; i < 2; i++ {
					select {
					case <-done:
						return
					case out1 <- val:
						out1 = nil
					case out2 <- val:
						out2 = nil
					}
				}
			}
		}()

		return out1, out2
	}
	done := make(chan interface{})
	go func() {
		time.Sleep(time.Second)
		close(done)
	}()
	out1, out2 := tee(done, take(done, repeat(done, 1, 2, 3), 2))
	for val1 := range out1 {
		fmt.Println("val1:", val1, " val2:", <-out2)
	}

}
